package com.lihaotian.calculate

import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    // lateinit 稍后初始化
    private lateinit var one: Button
    private lateinit var two: Button
    private lateinit var three: Button
    private lateinit var four: Button
    private lateinit var five: Button
    private lateinit var six: Button
    private lateinit var seven: Button
    private lateinit var eight: Button
    private lateinit var ninel: Button
    private lateinit var zero: Button
//
    private lateinit var dec: Button
    private lateinit var mul: Button
    private lateinit var div: Button
    private lateinit var app: Button

//
    private lateinit var content: EditText // 2.0中准备设计为预计准备运算答案的地方
    private lateinit var lastAns: TextView // 1.0中此处的位置是显示当前运算的结果，2.0打算改成每次运算后这里都清空，点完等号再显示结果，然后再次计算的时候这里再为空
//
    private lateinit var back: Button
    private lateinit var ac: Button
    private lateinit var ans: Button
    private lateinit var dot: Button

//
    private var isHasDot: Boolean = false // 这个每次输入数字得清空

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
        init()
        setNum()
        setCal()
        back.setOnClickListener {
            if (content.text.toString().isNotEmpty()) {
                if (content.text.toString().get(content.text.toString().length - 1) == '.') {
                    isHasDot = false
                }
                content.setText(content.text.delete(content.text.toString().length - 1, content.text.toString().length))
            }
        }

        dot.setOnClickListener {
            if (!isHasDot) {
                content.setText(content.text.toString() + ".")
                isHasDot = true
            }
        }

        ans.setOnClickListener {
            if (content.text.toString().get(0) == '+') {
                // 去掉头部的加号
                content.text.delete(0, 1)
            } else if (
                content.text.toString().get(content.length() - 1) == '×' ||
                content.text.toString().get(content.length() - 1) == '÷' ||
                content.text.toString().get(content.length() - 1) == '-' ||
                content.text.toString().get(content.length() - 1) == '+'
                ) {
                // 去掉末尾的运算符号
                content.text.delete(content.text.toString().length - 1, content.text.toString().length)
            }

            // 运算逻辑：从前往后运算，第一位要么是负号要么是个数，所以一视同仁，全都当成数开始就行了
            // 我查了一下官方内好像kotlin没有栈这个集合（？或者我没找到），所以我李浩天大王决定使用数组模拟栈
            // kotlin数组的语法 https://book.kotlincn.net/text/arrays.html
            var hhNum: Int = -1 // -1代表栈空, hhNum代表栈顶
            // 手写栈注意！添加是++hh，移除是--hh
            var hhCal: Int = -1
            val staNum = Array<Double>(100) { 0.0 } // 预设空间大小为100次运算
            val staCal = Array<Char>(100) { ' ' }
            var st: Int = 0
            var ed: Int = 0
            var calMulOrDiv: Boolean = false
            // 这里应该用双指针处理往栈中添加数据
            while (ed < content.text.toString().length) {
                while ((ed < content.text.toString().length &&
                    ((content.text.toString().get(ed) >= '0' && content.text.toString().get(ed) <= '9') ||
                    content.text.toString().get(ed) == '.')) ||
                    ed == 0) { // 这里的ed==0是为了处理首位符号为负号的情况
                    ed += 1
                }
                staNum[ ++ hhNum] = content.text.toString().substring(st, ed).toDouble()

                // 当前数进栈以后先看看上一位是不是乘除，需不需要处理
                if (calMulOrDiv) {
                    // 注意除法栈顶先出来的是被除数
                    var b: Double = staNum[hhNum -- ]
                    var a: Double = staNum[hhNum -- ]

                    var op: Char = staCal[hhCal -- ]
                    if (op == '×') {
                        staNum[ ++ hhNum] = a * b
                    } else {
                        staNum[ ++ hhNum] = a / b
                    }

                    calMulOrDiv = false
                }

                if (ed == content.text.toString().length) {
                    break
                }

                // 不是因为到末尾才结束的说明下一位是符号位
                st = ed
                ed  += 1

                var op = content.text.toString().substring(st, ed).toCharArray()[0]
                st = ed

                if (op == '×' || op == '÷') {
                    calMulOrDiv = true
                }
                staCal[ ++ hhCal] = op

            }

            // 全都处理完以后依次把所有运算符运行掉就行了
            while (hhCal >= 0) {
                var op: Char = staCal[hhCal -- ]
                var b: Double = staNum[hhNum -- ]
                var a: Double = staNum[hhNum -- ]
                if (op == '+') {
                    staNum[ ++ hhNum] = a + b
                } else {
                    staNum[ ++ hhNum] = a - b
                }
            }

            lastAns.setText(staNum[0].toString())
        }

        // 清空按钮
        ac.setOnClickListener {
            content.setText("")
            isHasDot = false
        }
    }

    // 初始化所有的运算符的点击监听
    fun setCal() {
        setCalClick(app)
        setCalClick(div)
        setCalClick(mul)
        setCalClick(dec)
    }

    // 设置运算符号的点击监听事件
    fun setCalClick(t: Button) {
        // 每次都点完计算按钮以后都清空小数点的计数
        t.setOnClickListener {
            // 如果点的是加或者减，那么直接添加的条件就是：首位 or 上位是数字或者小数点
            //                     替换的条件是：非首位且上位是符号
            if (t.text.toString() == "+" || t.text.toString() == "-") {
                if (content.text.isBlank() ||
                    content.text.get(content.length() - 1) == '.' ||
                    (content.text.get(content.length() - 1) >= '0' && content.text.get(content.length() - 1) <= '9')
                    ) {
                    content.setText(content.text.toString() + t.text.toString())
                } else {
                    content.setText(content.text.replace(content.text.toString().length - 1, content.text.toString().length, t.text.toString()))
                }
            }

            // 如果点的是乘或者除，直接添加的条件，非首位且上位是小数点或者数字
            //                  替换的条件，长度大于2且上位是符号位 （长度就1位然后上一位是加减的情况）
            if (t.text.toString() == "×" || t.text.toString() == "÷") {
                if (content.text.length >= 1 &&
                    (content.text.get(content.length() - 1) == '.' ||
                    (content.text.get(content.length() - 1) >= '0' && content.text.get(content.length() - 1) <= '9')
                    )) {
                    content.setText(content.text.toString() + t.text.toString())
                } else if (content.text.length >= 2) {
                    content.setText(content.text.replace(content.text.toString().length - 1, content.text.toString().length, t.text.toString()))
                }
            }
            isHasDot = false
        }
    }

    // 初始化所有数字按键的点击监听
    fun setNum() {
        setNumClick(one)
        setNumClick(two)
        setNumClick(three)
        setNumClick(four)
        setNumClick(five)
        setNumClick(six)
        setNumClick(seven)
        setNumClick(eight)
        setNumClick(ninel)
        setNumClick(zero)
    }

   // 给数字键添加点击添加监听
    fun setNumClick(t: Button) {
        t.setOnClickListener {
            content.setText(content.text.toString() + t.text.toString())
        }
    }

    // 初始化所有的按键
    fun init() {
        one = findViewById(R.id.one)
        two = findViewById(R.id.two)
        three = findViewById(R.id.three)
        four = findViewById(R.id.four)
        five = findViewById(R.id.five)
        six = findViewById(R.id.six)
        seven = findViewById(R.id.seven)
        eight = findViewById(R.id.eight)
        ninel = findViewById(R.id.ninel)
        zero = findViewById(R.id.zero)
//
        dec = findViewById(R.id.dec)
        mul = findViewById(R.id.mul)
        div = findViewById(R.id.div)
        app = findViewById(R.id.app)

//
        content = findViewById(R.id.content)
        lastAns = findViewById(R.id.lastAns)
//
        ans = findViewById(R.id.ans)
        ac = findViewById(R.id.AC)
        back = findViewById(R.id.back)
        dot = findViewById(R.id.dot)
    }
}